import { Container, Extract } from "pixi.js";
import { Canvas } from "../Canvas";
import { hub } from "../hub";
import { DataOfLayer, useControllerStore } from "../../Controller/Controller";
import { DrawEngine, nextReDrawTick } from "./DrawEngine";
import { Cover } from "./Cover";
import { debounce, omit, pick } from "lodash-es";
import { UserHub } from "../../UserInput/UserListener";
import { LayerPersistData } from "../Data/CanvasFile";
import { LayerManager } from "./LayerManager";
import { Meta } from "../Data/Meta";

/**这是绘制的一个图层 */
export class Layer extends DrawEngine {
    readonly id: string;
    private _userLock = false;
    set zIndex(index: number) {
        this.g.zIndex = index;
    }
    get zIndex() {
        return this.g.zIndex;
    }
    set alpha(alpha: number) {
        this.g.alpha = alpha;
    }
    get alpha() {
        return this.g.alpha;
    }
    set visible(visible: boolean) {
        this.g.visible = visible;
    }
    get visible() {
        return this.g.visible;
    }
    /** 用户加上的锁，防止交互事件的触发 */
    get userLock() {
        return this._userLock;
    }
    set userLock(lock: boolean) {
        this._userLock = lock;
        this.g.interactive = !lock;
    }
    /** 标记图层是否被选中 */
    selected = false;
    /** 图层被选中时的事件 */
    changeSelected = (ids: string[]) => {
        this.selected = ids.includes(this.id);
        hub.emit("updateLayer", this);
    };
    /** 初始化一个图层 */
    constructor(
        public canvas: Canvas,
        public name: string,
        design: LayerManager["design"],
        data?: LayerPersistData
    ) {
        super(design.width, design.height, design.tileSize);
        this.id = name + new Date().getTime();
        // 注入数据
        if (data) this.loadLayerData(data);

        hub.on("changeLayer", this.changeLayer);
        hub.on("selectLayer", this.changeSelected);
        UserHub.on("cancel", (id) => {
            if (id === this.id) {
                this.dataControl("cancel");
            }
        });
        UserHub.on("recover", (id) => {
            if (id === this.id) {
                this.dataControl("recover");
            }
        });
        nextReDrawTick(() => {
            // 选中这个图层，并关闭其他图层
            useControllerStore().selectLayer(this.id);
            this.reRenderEdge();
        });
    }

    reRenderEdge() {
        this.tileMap.autoRender(this.canvas.app);
    }

    /** 删除数据 */
    destroy() {
        super.destroy.call(this);
        hub.off("changeLayer", this.changeLayer);
        hub.off("selectLayer", this.changeSelected);
    }
    /** 外部改动 layer 内部的参数的方式 */
    changeLayer = ({
        id,
        data,
    }: {
        id: string;
        data: Partial<DataOfLayer>;
    }) => {
        if (id === this.id) {
            Object.assign(this, data);
            hub.emit("updateLayer", this);
        }
    };

    /** 将画布挂载到 Pixi */
    mount(app: Container, cover: Cover) {
        app.addChild(this.g);

        this.bindDraw(cover);
        // 如果不进行第一次添加，那么会出现奇怪的现象

        return this;
    }
    /** 判断是否能够被绘制 */
    canDraw() {
        return !this.userLock && this.g.visible && this.selected;
    }
    /** 绑定绘制事件到 cover 层 */
    protected bindDraw(cover: Cover) {
        // 但是下面的事件也是要销毁的
        cover
            .on("drawStart", this.drawStart)
            .on("drawEnd", this.drawEnd)
            .on("drawing", this.drawing);
    }

    /** 绘制时起点,这里需要debounce 的原因是这个函数会在某些情况下判断两次 */
    drawStart = debounce((data: any) => {
        if (!this.canDraw()) return;
        this.startRecord();
        console.log("绘制开始");
        hub.emit("drawStart", { layer: this, data });
    }, 10);
    pathSet = new Set();
    /** 绘制时终点 */
    drawEnd = (data: any) => {
        if (!this.canDraw()) return;
        this.stopRecord();
        hub.emit("drawEnd", { layer: this, data });
        this.pathSet.clear();
    };
    /** 绘制中事件，需要单独操作 */
    drawing = ({ x, y }: { x: number; y: number }) => {
        if (!this.canDraw()) return;
        if (x > this.g.width || y > this.g.height || x < 0 || y < 0) return;
        const posX = Math.floor(x);
        const posY = Math.floor(y);
        const path = `${posX},${posY}`;
        if (this.pathSet.has(path)) return;
        hub.emit("drawing", {
            layer: this,
            data: { x: posX, y: posY },
        });
        this.pathSet.add(path);
    };

    /** 创建一个截图，用于图层展示，可以传入图像质量 */
    createSnapshot(quality = 0.1) {
        const extract = this.canvas.app.renderer.plugins.extract as Extract;
        const data = extract.base64(this.g, "image/webp", quality);

        return data;
    }
    /** 撤销，重做功能 */
    dataControl(tag: "cancel" | "recover") {
        const changes = this.data[tag]();
        changes.forEach(([position, data]) =>
            this.replacePoint(...position, ...data)
        );
    }
    /** 导入数据 */
    loadLayerData(data: LayerPersistData) {
        Object.assign(this, omit(data, ["history"]));
        // 构建一个零时的绘制 Meta
        const step = this.data.reCreate(data.history.map((i) => new Meta(i)));
        console.log("导入图层数据完成", this.name);

        step.change.forEach(({ position, diff: [_, newValue] }) => {
            this.replacePoint(...position, ...newValue);
        });
    }
    /** 定义持久化操作 */
    public _toString(): LayerPersistData {
        const data = pick(this, ["id", "visible", "alpha", "userLock", "name"]);
        return { ...data, history: this.data.history };
    }
    toString() {
        return JSON.stringify(this._toString());
    }
}
